/*
	Origional Source from http://www.jankoatwarpspeed.com/post/2009/07/28/reinventing-drop-down-with-css-jquery.aspx
	Modified by Simeon Cheeseman
	
	You will need quicksilver.js and the fancydropbox.css stylesheet before this looks ok.
	
	Call it with a jQuery selector -> $("select").fancifyDropDown();
	Options are {onSelect: called when an element is selected, maxItems: max items in the filtered dropdown (default -1), if < 0 shows all}
*/
(function($) {
	//Static Defaults
	$.fancifydropdown = {
		config: {
			onSelect: null,
			maxItems: -1
		}
	}
	
	$.fn.fancifydropdown = function(config){
		config = $.extend({}, $.fancifydropdown.config, config);
		this.each(function(){
			var source = $(this);
			//hide origional drop box
			source.hide();
			var selected = source.find("option[selected]");
			var options = $(this).find("option");
			//add fancy dropbox after select
			$target = $('<dl class="dropdown"></dl>');
			
			$target.append('<dt><a href="#"><input class="filter" type="text" style="height: 18px;"><div>' + selected.text() + 
				'<span class="value">' + selected.val() + 
				'</span></div></a></dt>');
			$target.append('<dd><ul class="targetdata"></ul></dd>');
			//add all options
			var count = 1;
			options.each(function(){
				//uses attributes in the <option> tag, dispAfter and dispBefore that insert any html/text before or after the text in the option
				$target.find("dd ul").append('<li id="'+count+'"><a href="#">'
					+ ($(this).attr("dispBefore") == undefined ? "" : $(this).attr("dispBefore"))
					+ $(this).text()
					+ ($(this).attr("dispAfter") == undefined ? "" : $(this).attr("dispAfter"))
					+ '<span class="value">'
					+ $(this).val() + '</span></a></li>');
					count += 1;
			});
			
			$target.find('dd ul li').slice(config.maxItems).hide();
			
			//show/hide if clicked in the main box
			$target.find("dt a").click(function() {
				$(".dropdown").not($(this).closest(".dropdown")).each(function(){
					$(this).find("dd ul").slideUp();
				    $(this).find("dt a input").hide();
					$(this).find("dt a div").show();
				});
				$(this).closest(".dropdown").find("dd ul").slideToggle();
				$(this).find("input").toggle().focus();
				$(this).find("div").toggle();
				return false;
			});
			//hide if clicked outside of
			$(document).bind('click', function(e) {
				var $clicked = $(e.target);
				if (! $clicked.parents().hasClass("dropdown")){
				    $(".dropdown dd ul").slideUp();
				    $(".dropdown dt a input").hide();
					$(".dropdown dt a div").show();
				}
			});
			//hide when selected and update display and drop box
			$target.find("dd ul li a").click(function() {
				var text = $(this).html(), $dropdown = $(this).closest(".dropdown");
				$dropdown.prev().val($(this).find("span.value").html()).change();
				$dropdown.find("dt a div").html(text);
				$dropdown.find("dd ul").slideUp();
				$dropdown.find("dt a input").hide();
				$dropdown.find("dt a div").show();
				if (config.onSelect && config.onSelect.call($(this)) === false) { return this; }
			});
			$target.find("dd a").hover(function(){$(this).addClass("hover")}, function(){$(this).removeClass("hover")});
			//key traversal
			$target.find("dt a input").keydown(function(evt){
				var $visibles = $(this).closest(".dropdown").find("dd li:visible");
				var $current = $visibles.find(".hover");
				if(evt.keyCode == 38){
					//up key
					if($current.length == 1){
						if($current.parent().prev().length != 0){
							$current.parent().prev().find("a").addClass("hover");
							$current.removeClass("hover");
						}
					}else{
						$visibles.last().find("a").addClass("hover");
					}
				}else if(evt.keyCode == 40){
					//down key
					if($current.length == 1){
						if($current.parent().next(":visible").length != 0){
							$current.parent().next().find("a").addClass("hover");
							$current.removeClass("hover");
						}
					}else{
						$visibles.first().find("a").addClass("hover");
					}
				}else if(evt.keyCode == 13){
					//enter key
					$current.click();
				}
				return false;
			});
			//Smart filtering
			$target.find('.filter').liveUpdate($target.find('.targetdata'), config.maxItems).focus();
			
			$(this).after($target);
		});
	}
	
	//Smart filtering from quicksilver.js
	$.fn.liveUpdate = function(list, max){
		if ( list.length ) {
			var rows = list.children('li'),
				cache = rows.map(function(){
					return this.innerHTML.toLowerCase().replace(/<.*?>/g, " ");
				});
			this.change(filter).keyup(function(){$(this).change()}).click(function(){$(this).change();});
		}
			
		return this;
			
		function filter(){
			var term = jQuery.trim( jQuery(this).val().toLowerCase() ), scores = [];
			
			if ( !term ) {
				rows.each(function(){jQuery(this).parent().append(this)})
				rows.hide();
				rows.slice(0, max).show();
			} else {
				cache.each(function(i){
					var score = this.score(term);
					scores.push([score, i]);
				});
				
				var counter = 0;
				var prev = null;
				jQuery.each(scores.sort(function(a, b){return b[0] - a[0];}), function(){
					var element = jQuery(rows[this[1]]);
					if(prev == null)jQuery(element).parent().append(element);
					else jQuery(prev).after(element);
					if(this[0] > 0 && (counter < max || max < 0)) jQuery(element).show();
					else element.hide();
					prev = element;
					counter++;
				});
			}
		}
	};
})(jQuery);